package com.lhkj.ct.framework.filter;

import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import java.io.IOException;
import java.util.*;

/**
 * IP过滤器
 */

@SuppressWarnings("unchecked")
@WebFilter(urlPatterns = {"/*"}, filterName = "bFilter")
public class IpFilter implements Filter {

    private FilterConfig config;

//    private XTSZService xtszService;

    private List<String> rulesList;

    @Override
    public void init(FilterConfig filterConfig) {
        this.config = filterConfig;
//        this.xtszService = ApplicationContextHelper.getBean(XTSZServiceImpl.class);
        this.rulesList = new ArrayList<>();
        this.rulesList.add("/styles/**");
        this.rulesList.add("/error/**");
    }

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain chain) throws IOException, ServletException {
//        XTSZVo xtszVo = xtszService.selectOne();
//        HttpServletRequest request = (HttpServletRequest) servletRequest;
//        HttpServletResponse response = (HttpServletResponse) servletResponse;
//        if (xtszVo.getIP_STATE() == 0) {
//            chain.doFilter(request, response);
//            return;
//        }
//        // 是否排除url
//        String path = request.getContextPath();
//        String requestURI = request.getRequestURI();
//        requestURI = requestURI.substring(path.length());
//        String finalRequestURI = requestURI;
//        if (rulesList.stream().anyMatch(p -> UrlUtils.checkWhiteList(rulesList, finalRequestURI))) {
//            chain.doFilter(request, response);
//            return;
//        }
//        // 获取用户IP
//        String clientIp = RequestUtil.getClientIp();
//        List<String> wips = new ArrayList<>(xtszVo.getIP_WHITE_LIST());
//        // 是否IP白单名访问
//        String finalClientIp = clientIp;
//        if (wips.stream().anyMatch(p -> RequestUtil.validIp(p, finalClientIp))) {
//            chain.doFilter(request, response);
//            return;
//        }
//        // 是否IP黑单名访问
//        List<String> bips = new ArrayList<>(xtszVo.getIP_BLACK_LIST());
//        if (bips.stream().anyMatch(p -> RequestUtil.validIp(p, finalClientIp))) {
//            if (RequestUtil.isAjax(request)) {
//                RequestUtil.printWriter(response, new JsonResult<>(ResultStatus.CODE_403, "存在恶意请求，已被系统拦截"));
//            } else {
//                String error = URLEncoderUtil.encode(URLEncoderUtil.encode("存在恶意请求，已被系统拦截"));
//                request.getRequestDispatcher("/error/403?error=" + error).forward(request, response);
//                chain.doFilter(request, response);
//            }
//            return;
//        }
//        ServletContext context = config.getServletContext();
//        // 获取限制IP存储器：存储被限制的IP信息
//        Map<String, Long> limitedIpMap = (Map<String, Long>) context.getAttribute("limitedIpMap");
//        if (limitedIpMap == null) {
//            limitedIpMap = new HashMap<>();
//        }
//        // 过滤受限的IP
//        filterLimitedIpMap(limitedIpMap);
//        // 根据ip及请求路径
//        clientIp = clientIp + "-" + requestURI;
//        // 判断是否是被限制的IP，如果是则跳到异常页面
//        if (isLimitedIP(limitedIpMap, clientIp)) {
//            JsonResult<String> result = new JsonResult<>(ResultStatus.CODE_403, "请求过于频繁，请稍后再试");
//            JSONUtil.writeJson(response, result);
//            return;
//        }
//        // 获取IP存储器
//        Map<String, Long[]> ipMap = (Map<String, Long[]>) context.getAttribute("ipMap");
//        if (ipMap == null) {
//            ipMap = new HashMap<>();
//        }
//        if (ipMap.containsKey(clientIp)) {
//            Long[] ipInfo = ipMap.get(clientIp);
//            ipInfo[0] = ipInfo[0] + 1;
//            if (ipInfo[0] > xtszVo.getIP_LIMITNUMBER()) {
//                long ipAccessTime = ipInfo[1];
//                long currentTimeMillis = System.currentTimeMillis();
//                if (currentTimeMillis - ipAccessTime <= xtszVo.getIP_MINSAFETIME()) {
//                    limitedIpMap.put(clientIp, currentTimeMillis + xtszVo.getIP_LIMITEDTIME());
//                    context.setAttribute("limitedIpMap", limitedIpMap);
//                    JsonResult<String> result = new JsonResult<>(ResultStatus.CODE_403, "请求过于频繁，请稍后再试");
//                    JSONUtil.writeJson(response, result);
//                    return;
//                } else {
//                    initIpVisitsNumber(ipMap, clientIp);
//                }
//            }
//        } else {
//            initIpVisitsNumber(ipMap, clientIp);
//        }
//        context.setAttribute("ipMap", ipMap);
        chain.doFilter(servletRequest, servletResponse);
    }

    @Override
    public void destroy() {

    }

    /**
     * @param limitedIpMap
     * @Description 过滤受限的IP，剔除已经到期的限制IP
     */
    private void filterLimitedIpMap(Map<String, Long> limitedIpMap) {
        if (limitedIpMap == null) {
            return;
        }
        Set<String> keys = limitedIpMap.keySet();
        Iterator<String> keyIt = keys.iterator();
        long currentTimeMillis = System.currentTimeMillis();
        while (keyIt.hasNext()) {
            long expireTimeMillis = limitedIpMap.get(keyIt.next());
            if (expireTimeMillis <= currentTimeMillis) {
                keyIt.remove();
            }
        }
    }

    /**
     * 获取IP状态
     *
     * @param limitedIpMap
     * @param ip
     * @return true : 被限制 | false : 正常
     * @Description 是否是被限制的IP
     */
    private boolean isLimitedIP(Map<String, Long> limitedIpMap, String ip) {
        if (limitedIpMap == null || ip == null) {
            // 没有被限制
            return false;
        }
        Set<String> keys = limitedIpMap.keySet();
        for (String key : keys) {
            if (key.equals(ip)) {
                // 被限制的IP
                return true;
            }
        }
        return false;
    }

    /**
     * 初始化用户访问次数和访问时间
     *
     * @param ipMap
     * @param ip
     */
    private void initIpVisitsNumber(Map<String, Long[]> ipMap, String ip) {
        Long[] ipInfo = new Long[2];
        ipInfo[0] = 0L;// 访问次数
        ipInfo[1] = System.currentTimeMillis();// 初次访问时间
        ipMap.put(ip, ipInfo);
    }
}
